# -*- coding: utf-8 -*-
"""
# @created on : 9月 2021/9/25 13:19
# @author     : kevin
# @file       : web_key.py
# @software   : PyCharm
# @project    : auto_keyword_data


@license: (C) Copyright 2019-2025, Corporation Limited.
@desc:将常用的/常规的操作行为封装成自定义的关键字函数，在执行自动化的时候，通过调调用自定义函数类，来实现自动化操作。
"""
import os.path
import time
import traceback
from PIL import Image

from selenium import webdriver
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as ec
from selenium.webdriver.support.ui import Select
from common.log import Logger
from utils.path import OperationPath
from common.num import CreatNum
from base.variable import OperationVariable


def browser(type_):
    try:
        driver = getattr(webdriver, type_.capitalize())()
    except:
        driver = webdriver.Chrome()
    finally:
        return driver


class WebKey:
    def __init__(self, type_):
        self.driver = browser(type_)
        self.log = Logger()
        self.path = OperationPath()
        self.rand = CreatNum()
        self.variable = OperationVariable()

    def my_wait(self, locator):
        WebDriverWait(self.driver, 20, 0.1).until(ec.presence_of_element_located(locator))

    def open(self, **kwargs):
        """
        打开输入值指定的地址
        :param kwargs:
        :return:
        """
        self.driver.get(kwargs.get('输入值'))

    def maximize(self, **kwargs):
        """
        最大化窗口
        :param kwargs:
        :return:
        """
        self.driver.maximize_window()

    def minimize(self, **kwargs):
        """
        最小化窗口
        :param kwargs:
        :return:
        """
        self.driver.minimize_window()

    def set_windows_size(self, **kwargs):
        """
        设置窗口尺寸，通过输入值传入要指定的窗口尺寸
        :param kwargs: 窗口尺寸，例如：1024,768
        :return:
        """
        self.driver.set_window_size(kwargs.get('输入值'))

    def frward(self, **kwargs):
        """
        控制浏览器前进
        :param kwargs:
        :return:
        """
        self.driver.forward()

    def back(self, **kwargs):
        """
        控制浏览器后退
        :param kwargs:
        :return:
        """
        self.driver.back()

    def locator(self, method, path):
        """
        获取元素
        :param method:
        :param path:
        :return:
        """
        locator = self.driver.find_element(method, path)
        return locator

    def input(self, **kwargs):
        """
        指定元素位置输入值，会先清空原位置，再判断输入值是否以$开头，如果以$开头则被定义为变量值，
        会先去变量列表中找到变量对应的值，替换原输入值，否则则直接原值输入
        :param kwargs:
        :return:
        """
        self.locator(kwargs.get('定位方式'), kwargs.get('定位路径')).clear()
        if str(kwargs.get('输入值')).startswith('$'):
            values = self.variable.get_value_from_key_value(str(kwargs.get('输入值')).lstrip('$'))
        else:
            values = kwargs.get('输入值')
        self.locator(kwargs.get('定位方式'), kwargs.get('定位路径')).send_keys(values)

    def execute_script(self, **kwargs):
        """
        执行指定的脚本，脚本内容直接写入输入值内即可
        :param kwargs:
        :return:
        """
        self.driver.execute_script(kwargs.get('输入值'))

    def select_by_index(self, **kwargs):
        """
        按照选择的顺序进行选择，第一个选项index值为0
        :param kwargs:
        :return:
        """
        Select(self.locator(kwargs.get('定位方式'), kwargs.get('定位路径'))).select_by_index(kwargs.get('输入值'))

    def deselect_by_index(self, **kwargs):
        """
        按照选择的顺序进行反选，第一个选项index值为0
        :param kwargs:
        :return:
        """
        Select(self.locator(kwargs.get('定位方式'), kwargs.get('定位路径'))).deselect_by_index(kwargs.get('输入值'))

    def select_by_value(self, **kwargs):
        """
        按照value属性来进行选择
        :param kwargs:
        :return:
        """
        Select(self.locator(kwargs.get('定位方式'), kwargs.get('定位路径'))).select_by_value(kwargs.get('输入值'))

    def deselect_by_value(self, **kwargs):
        """
         按照value属性来进行反选
        :param kwargs:
        :return:
        """
        Select(self.locator(kwargs.get('定位方式'), kwargs.get('定位路径'))).deselect_by_value(kwargs.get('输入值'))

    def select_by_visible_text(self, **kwargs):
        """
         按照选项的可见文本来进行选择
        :param kwargs:
        :return:
        """
        Select(self.locator(kwargs.get('定位方式'), kwargs.get('定位路径'))).select_by_visible_text(kwargs.get('输入值'))

    def deselect_by_visible_text(self, **kwargs):
        """
        按照选项的可见文本来进行反选
        :param kwargs:
        :return:
        """
        Select(self.locator(kwargs.get('定位方式'), kwargs.get('定位路径'))).deselect_by_visible_text(kwargs.get('输入值'))

    def click(self, **kwargs):
        """
        点击指定的元素
        :param kwargs:
        :return:
        """
        self.locator(kwargs.get('定位方式'), kwargs.get('定位路径')).click()

    def get_element_value(self, **kwargs):
        """
        获取元素标签内容
        :param kwargs:
        :return:
        """
        s = self.locator(kwargs.get('定位方式'), kwargs.get('定位路径'))
        return s.text

    def get_element_attr(self, **kwargs):
        """
        获取指定的元素的某属性的内容，属性类型在输入值中定义
        :param kwargs:
        :return:
        """
        return self.locator(kwargs.get('定位方式'), kwargs.get('定位路径')).get_attribute(kwargs.get('输入值'))

    def fresh(self, **kwargs):
        """
        刷新页面
        :param kwargs:
        :return:
        """
        self.driver.refresh()

    def submit(self, **kwargs):
        """
        提交表单
        :param kwargs:
        :return:
        """
        self.locator(kwargs.get('定位方式'), kwargs.get('定位路径')).submit()

    def switch_ifream(self, **kwargs):
        """
        切换ifream到指定输入值指定的ifream
        :param kwargs:
        :return:
        """
        self.driver.switch_to.frame(kwargs.get('输入值'))

    def switch_to_default(self, **kwargs):
        """
        切换到默认页面
        :return:
        """
        self.driver.switch_to.default_content()

    def switch_to_parent(self, **kwargs):
        """
        切换到父级fream
        :return:
        """
        self.driver.switch_to.parent_frame()

    def switch_to_alert(self, **kwargs):
        """
        切换到弹窗
        :return:
        """
        alert = self.driver.switch_to.alert()
        return alert

    def get_alert_text(self, **kwargs):
        """
        获取提示框文本
        :return: 提示框文本
        """
        alert = self.switch_to_alert()
        return alert.text

    def accept_alert(self, **kwargs):
        """
        确认提示框
        :return:
        """
        alert = self.switch_to_alert()
        alert.accept()

    def alert_auth(self, **kwargs):
        """
        向一个认证对话框发送用户名和密码,还没有调试过的函数，暂时输入是按照input方式来处理的
        :param username: 用户名
        :param password: 密码
        :return:
        """
        alert = self.switch_to_alert()
        alert.authenticate(kwargs.get('输入值'))

    def alert_send_text(self, **kwargs):
        """
        向对话框输入文本
        :param text: 要输入的文本
        :return:
        """
        alert = self.switch_to_alert()
        alert.send_keys(kwargs.get('输入值'))

    def dis_alert(self, **kwargs):
        """
        忽略提示框
        :return:
        """
        alert = self.switch_to_alert()
        alert.dismiss()

    def get_windows_handle(self, **kwargs):
        """
        获取所有窗口句柄并返回
        :return: 窗口句柄
        """
        handles = self.driver.window_handles
        return handles

    def switch_to_windows(self, **kwargs):
        """
        将当前窗口切换到指定句柄的窗口
        :param handle: 窗口句柄
        :return:
        """
        self.driver.switch_to.window(kwargs.get('输入值'))

    def topics(self, **kwargs):
        """
        判断当前焦点是否为指定的焦点
        :param locator: 指定焦点
        :return: 是则返回True,否则返回False
        """
        flg = False
        if self.driver.switch_to.active_element == self.locator(kwargs.get('定位方式'), kwargs.get('定位路径')):
            flg = True
        return flg

    def active_element_sent_key(self, **kwargs):
        """
        在当前焦点位置输入内容
        :param text: 当前焦点要输入的值
        :return:
        """
        self.driver.switch_to.active_element.send_keys(kwargs.get('输入值'))

    def time_sleep(self, **kwargs):
        """
        强制等待一定事件
        :param kwargs:
        :return:
        """
        time.sleep(kwargs.get('输入值'))

    def close(self, **kwargs):
        """
        关闭
        :return:
        """
        self.driver.close()

    def quit(self, **kwargs):
        """
        退出
        :return:
        """
        self.driver.quit()

    def exec_assert(self, **kwargs):
        assert_type = str(kwargs.get('断言')).split('=')[0]
        value = str(kwargs.get('断言')).split('=')[1]
        flg = False
        if assert_type == 'assert_location':
            pass
        elif assert_type == 'assert_title':
            pass
        elif assert_type == 'assert_value':
            pass
        elif assert_type == 'assert_selected':
            pass
        elif assert_type == 'assert_text':
            web_value = self.get_element_value(**kwargs)
            print(f'web find element value is {web_value}')
            if web_value == value:
                flg = True
        elif assert_type == 'assert_text_present':
            pass
        elif assert_type == 'assert_text_not_present':
            pass
        elif assert_type == 'assert_attribute':
            pass
        elif assert_type == 'assert_table':
            pass
        elif assert_type == 'assert_editable':
            pass
        elif assert_type == 'assert_not_editable':
            pass
        elif assert_type == 'assert_alert':
            pass
        else:
            pass
        return flg



    def screen_short(self, **kwargs):
        """
        截图
        :param kwargs:
        :return:
        """
        screen_path = os.path.join(self.path.get_current_path(), 'result', 'screen', self.rand.today)
        self.path.check_path(screen_path)
        file_name = self.rand.creat_random_string(5) + '.png'
        file_path = os.path.join(screen_path, file_name)
        try:
            self.driver.save_screenshot(file_path)
        except:
            self.log.logger('error', f'截图发生异常{file_path},\n 错误信息如下：{traceback.format_exc()}')
        finally:
            return file_path

    def img_valid(self, **kwargs):
        valid_path = os.path.join(self.path.get_current_path(), 'result', 'valid', self.rand.today)
        self.path.check_path(valid_path)
        valid_name = self.rand.creat_random_string(5) + '.png'
        valid_path_name = os.path.join(valid_path, valid_name)
        scree_file = self.screen_short(**kwargs)
        while(self.path.check_file(scree_file)):
            img = Image.open(scree_file)
            element = self.locator(kwargs.get('定位方式'), kwargs.get('定位路径'))
            left = element.location['x'] * 2
            top = element.location['y'] * 2
            right = element.size['width'] * 2 + left
            bottom = element.size['height'] * 2 + top
            img.crop((left, top, right, bottom)).save(valid_path_name)
            while(self.path.check_file(valid_path_name)):
                with open(valid_path_name, 'rb') as f:
                    img_bytes = f.read()
                res = self.variable.update_variable(str(kwargs.get('输入值')).lstrip('$')+'=imgvalid', img_bytes)
                if res:
                    break
            if res:
                break
